package suncertify.ui;

import java.awt.Container;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;

import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JTextField;
import javax.swing.filechooser.FileNameExtensionFilter;

import suncertify.controller.ServerGuiController;
import suncertify.db.Data;
import suncertify.db.InvalidArgumentException;
import suncertify.resources.App;
import suncertify.resources.ConfigurationIO;

/**
 * The GUI that will get all the required information to run the application.
 * This GUI will change dynamically based upon the mode in which the user ran the application.  
 * It will allow them in different modes to either enter their DB Location, Host, or Port.
 * @author Paul Wilhelm
 *
 */
public class ServerGui {
	
	private JFrame frame;
	private GridBagConstraints constraint;
	private JTextField dbTxt;
	private JTextField portTxt;
	private JTextField serverTxt;
	private JButton elipse;
	private ServerGuiController controller;			//The controller to handle all the user events
	private static ServerGui INSTANCE;				//A singleton instance of the class
	
	//Private, not a requirement to document
	private ServerGui(){	
		frame = new JFrame();
		frame.setTitle("Remote Server Properties");
		frame.setPreferredSize(new Dimension(400,250));
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.setResizable(false);
		controller = new ServerGuiController();
		frame.setIconImage(App.icon);
		constraint = new GridBagConstraints();
	}
	
	/**
	 * A singleton method. Creates a new <code>ServerGui</code> object if non exists. Otherwise
	 * will return the object already in memory.
	 * @return The ServerGui object to be used by the application
	 */
	public static ServerGui getInstance(){
		if (INSTANCE == null){
			INSTANCE = new ServerGui();
		}
		return INSTANCE;
	}
	
	/**
	 * Builds the view for the user to interact with, then displays it.
	 */
	public void buildAndShowGui(){
		Container mainPanel = frame.getContentPane();
		mainPanel.setLayout(new GridBagLayout());

		constraint.gridx = 0;
		constraint.gridy = 0;
		constraint.gridwidth = 2;
		constraint.fill = GridBagConstraints.HORIZONTAL;
		constraint.weightx = 1;
		constraint.insets = new Insets(20, 80, 20, 0);
		JLabel descriptionLbl = new JLabel("<HTML>Please enter the following information.</HTML>");
		mainPanel.add(descriptionLbl, constraint);
		
		//reset the constraints from above
		constraint.insets = new Insets(5, 5, 5, 5);
		constraint.gridwidth = 1;
		constraint.weightx = 0;
		
		constraint.gridx = 0;
		constraint.gridy = 1;
		JLabel dbLbl = new JLabel("Database Location: ");
		mainPanel.add(dbLbl, constraint);
		
		constraint.gridx = 1;
		constraint.gridy = 1;
		dbTxt = new JTextField();
		dbTxt.setColumns(20);
		mainPanel.add(dbTxt, constraint);
		
		constraint.gridx = 2;
		constraint.gridy = 1;
		elipse = new JButton("<HTML><b>...</b></HTML>");
		mainPanel.add(elipse, constraint);
		elipse.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				JFileChooser chooser = new JFileChooser();
				FileNameExtensionFilter filter = new FileNameExtensionFilter("Database Files", "db");
				chooser.setFileFilter(filter);
				chooser.showDialog(dbTxt, "Select File");
				if (chooser.getSelectedFile() != null){
					dbTxt.setText(chooser.getSelectedFile().getAbsolutePath());
				}
			}
		});
		
		constraint.gridx = 0;
		constraint.gridy = 2;
		JLabel serverLbl = new JLabel("Server Location: ");
		mainPanel.add(serverLbl, constraint);
		
		constraint.gridx = 1;
		constraint.gridy = 2;
		serverTxt = new JTextField();
		serverTxt.setColumns(20);
		mainPanel.add(serverTxt, constraint);
		
		constraint.gridx = 0;
		constraint.gridy = 3;
		JLabel portLbl = new JLabel("Port: ");
		mainPanel.add(portLbl, constraint);
		
		constraint.gridx = 1;
		constraint.gridy = 3;
		portTxt = new JTextField();
		portTxt.setColumns(20);
		mainPanel.add(portTxt, constraint);
		
		constraint.gridx = 0;
		constraint.gridy = 4;
		constraint.insets = new Insets(20, 20, 20, 20);
		JButton saveBtn = new JButton("Save");
		mainPanel.add(saveBtn, constraint);
		saveBtn.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				if ((App.isServer || App.isAlone) && dbTxt.getText().equals("")){   //If running in server or alone mode, and they didn't enter a DB location.
					JOptionPane.showMessageDialog(null, "You need to enter the database location");
					return;
				}
				if (App.isNetworked && serverTxt.getText().equals("")){		//If running in networked mode and they didn't enter a server location
					JOptionPane.showMessageDialog(null, "You need to enter the server location");
					return;
				}
				if ((App.isNetworked || App.isServer) && portTxt.getText().equals("")){	//If running in networked or server mode and they didn't enter a port.
					JOptionPane.showMessageDialog(null, "You need to enter the port number");
					return;
				}
				try {
					App.dbLocation = dbTxt.getText();
					App.host = serverTxt.getText();
					Data data = Data.getInstance();
					data.loadDbFile(App.dbLocation);			//Used to verify the database file
					data.getAllRooms();
					try {
						if (App.isNetworked || App.isServer){		//If running in networked or server mode
							App.port = Integer.parseInt(portTxt.getText());
						}
					} catch (NumberFormatException ex){
						JOptionPane.showMessageDialog(null, "Please make sure you enter a valid port number");
					}
					controller.onSaveClick();
				} catch (FileNotFoundException fnfe){
					JOptionPane.showMessageDialog(null, "There was a problem finding / loading the database file");
				} catch (RemoteException re){
					if (App.isServer) {		//If running in server mode
						JOptionPane.showMessageDialog(null, "Unable to start the server");
					}
					else {		//If running in networked mode
						JOptionPane.showMessageDialog(null, "Could not connect to remote database");
					}
				} catch (NotBoundException nbe){
					JOptionPane.showMessageDialog(null, "Could not find the database registry");
				} catch (IOException ioe){
					JOptionPane.showMessageDialog(null, "Could not validate data file.");
				} catch (IllegalArgumentException iae){
					JOptionPane.showMessageDialog(null, "You have entered a port that is out of range.");
				}
			}
		});
		
		if (App.isNetworked){		//If running in networked mode
			mainPanel.remove(dbLbl);
			mainPanel.remove(dbTxt);
			mainPanel.remove(elipse);
		}
		
		if (App.isServer){			//If running in server mode
			mainPanel.remove(serverLbl);
			mainPanel.remove(serverTxt);
		}
		
		if (App.isAlone){			//If running in alone mode
			mainPanel.remove(serverLbl);
			mainPanel.remove(serverTxt);
			mainPanel.remove(portLbl);
			mainPanel.remove(portTxt);
		}
		if (App.propertiesFile.exists()){		//If properties file exists, open and read it.
			try {
				String[] props = ConfigurationIO.readPropFile();
				dbTxt.setText(props[0]);
				serverTxt.setText(props[1]);
				portTxt.setText(props[2]);
			} catch (IOException ioe){
				JOptionPane.showMessageDialog(null, "Could not read properties file");
				ioe.printStackTrace();
			}
		}
		frame.pack();
		frame.setVisible(true);
	}
	
	/**
	 * Closes the view and releases of all the components from memory.
	 */
	public void closeGui(){
		frame.dispose();
	}
	
	/**
	 * The entry point for the application.  This will start the application.
	 * @param args - Can be either 'alone' server' or blank
	 */
	public static void main(String[] args) {
		ServerGui gui = ServerGui.getInstance();
		if (args.length <= 1){
			if (args.length == 0){		//Running in networked mode
				App.isNetworked = true;
				gui.buildAndShowGui();
				return;
			}
			else if (args[0].equals("server")){		//If running in server mode
				App.isServer = true;
				gui.buildAndShowGui();
			}
			else if (args[0].equals("alone")){		//If running in alone mode
				App.isAlone = true;
				gui.buildAndShowGui();
			}
			else{			//If there is 1 argument, but it doesn't match any recognizable arguments
				try{
					throw new InvalidArgumentException();
				} catch (InvalidArgumentException e){
					System.out.println(e.getMessage());
				}
			}
		}
		else {				//If not running in any recognizable mode
			try{
				throw new InvalidArgumentException();
			} catch(InvalidArgumentException e){
				System.out.println(e.getMessage());
			}
		}
	}
	
	
	

}
